#ifndef THINK_THINK_DB_BUILDER_H
#define THINK_THINK_DB_BUILDER_H

static char* think_db_builder =
	"\n"
	"// +----------------------------------------------------------------------\n"
	"// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n"
	"// +----------------------------------------------------------------------\n"
	"// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.\n"
	"// +----------------------------------------------------------------------\n"
	"// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n"
	"// +----------------------------------------------------------------------\n"
	"// | Author: liu21st <liu21st@gmail.com>\n"
	"// +----------------------------------------------------------------------\n"
	"\n"
	"namespace think\\db;\n"
	"\n"
	"use PDO;\n"
	"use think\\Exception;\n"
	"\n"
	"abstract class Builder\n"
	"{\n"
	"    // connection对象实例\n"
	"    protected $connection;\n"
	"    // 查询对象实例\n"
	"    protected $query;\n"
	"\n"
	"    // 数据库表达式\n"
	"    protected $exp = [\'eq\' => \'=\', \'neq\' => \'<>\', \'gt\' => \'>\', \'egt\' => \'>=\', \'lt\' => \'<\', \'elt\' => \'<=\', \'notlike\' => \'NOT LIKE\', \'not like\' => \'NOT LIKE\', \'like\' => \'LIKE\', \'in\' => \'IN\', \'exp\' => \'EXP\', \'notin\' => \'NOT IN\', \'not in\' => \'NOT IN\', \'between\' => \'BETWEEN\', \'not between\' => \'NOT BETWEEN\', \'notbetween\' => \'NOT BETWEEN\', \'exists\' => \'EXISTS\', \'notexists\' => \'NOT EXISTS\', \'not exists\' => \'NOT EXISTS\', \'null\' => \'NULL\', \'notnull\' => \'NOT NULL\', \'not null\' => \'NOT NULL\', \'> time\' => \'> TIME\', \'< time\' => \'< TIME\', \'>= time\' => \'>= TIME\', \'<= time\' => \'<= TIME\', \'between time\' => \'BETWEEN TIME\', \'not between time\' => \'NOT BETWEEN TIME\', \'notbetween time\' => \'NOT BETWEEN TIME\'];\n"
	"\n"
	"    // SQL表达式\n"
	"    protected $selectSql    = \'SELECT%DISTINCT% %FIELD% FROM %TABLE%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%UNION%%ORDER%%LIMIT%%LOCK%%COMMENT%\';\n"
	"    protected $insertSql    = \'%INSERT% INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%\';\n"
	"    protected $insertAllSql = \'%INSERT% INTO %TABLE% (%FIELD%) %DATA% %COMMENT%\';\n"
	"    protected $updateSql    = \'UPDATE %TABLE% SET %SET% %JOIN% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%\';\n"
	"    protected $deleteSql    = \'DELETE FROM %TABLE% %USING% %JOIN% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%\';\n"
	"\n"
	"    /**\n"
	"     * 构造函数\n"
	"     * @access public\n"
	"     * @param Connection    $connection 数据库连接对象实例\n"
	"     * @param Query         $query      数据库查询对象实例\n"
	"     */\n"
	"    public function __construct(Connection $connection, Query $query)\n"
	"    {\n"
	"        $this->connection = $connection;\n"
	"        $this->query      = $query;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 获取当前的连接对象实例\n"
	"     * @access public\n"
	"     * @return Connection\n"
	"     */\n"
	"    public function getConnection()\n"
	"    {\n"
	"        return $this->connection;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 获取当前的Query对象实例\n"
	"     * @access public\n"
	"     * @return Query\n"
	"     */\n"
	"    public function getQuery()\n"
	"    {\n"
	"        return $this->query;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 将SQL语句中的__TABLE_NAME__字符串替换成带前缀的表名（小写）\n"
	"     * @access protected\n"
	"     * @param string $sql sql语句\n"
	"     * @return string\n"
	"     */\n"
	"    protected function parseSqlTable($sql)\n"
	"    {\n"
	"        return $this->query->parseSqlTable($sql);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 数据分析\n"
	"     * @access protected\n"
	"     * @param array     $data 数据\n"
	"     * @param array     $options 查询参数\n"
	"     * @return array\n"
	"     * @throws Exception\n"
	"     */\n"
	"    protected function parseData($data, $options)\n"
	"    {\n"
	"        if (empty($data)) {\n"
	"            return [];\n"
	"        }\n"
	"\n"
	"        // 获取绑定信息\n"
	"        $bind = $this->query->getFieldsBind($options[\'table\']);\n"
	"        if (\'*\' == $options[\'field\']) {\n"
	"            $fields = array_keys($bind);\n"
	"        } else {\n"
	"            $fields = $options[\'field\'];\n"
	"        }\n"
	"\n"
	"        $result = [];\n"
	"        foreach ($data as $key => $val) {\n"
	"            if (\'*\' != $options[\'field\'] && !in_array($key, $fields, true)) {\n"
	"                continue;\n"
	"            }\n"
	"\n"
	"            $item = $this->parseKey($key, $options, true);\n"
	"            if ($val instanceof Expression) {\n"
	"                $result[$item] = $val->getValue();\n"
	"                continue;\n"
	"            } elseif (is_object($val) && method_exists($val, \'__toString\')) {\n"
	"                // 对象数据写入\n"
	"                $val = $val->__toString();\n"
	"            }\n"
	"            if (false === strpos($key, \'.\') && !in_array($key, $fields, true)) {\n"
	"                if ($options[\'strict\']) {\n"
	"                    throw new Exception(\'fields not exists:[\' . $key . \']\');\n"
	"                }\n"
	"            } elseif (is_null($val)) {\n"
	"                $result[$item] = \'NULL\';\n"
	"            } elseif (is_array($val) && !empty($val)) {\n"
	"                switch (strtolower($val[0])) {\n"
	"                    case \'inc\':\n"
	"                        $result[$item] = $item . \'+\' . floatval($val[1]);\n"
	"                        break;\n"
	"                    case \'dec\':\n"
	"                        $result[$item] = $item . \'-\' . floatval($val[1]);\n"
	"                        break;\n"
	"                    case \'exp\':\n"
	"                        throw new Exception(\'not support data:[\' . $val[0] . \']\');\n"
	"                }\n"
	"            } elseif (is_scalar($val)) {\n"
	"                // 过滤非标量数据\n"
	"                if (0 === strpos($val, \':\') && $this->query->isBind(substr($val, 1))) {\n"
	"                    $result[$item] = $val;\n"
	"                } else {\n"
	"                    $key = str_replace(\'.\', \'_\', $key);\n"
	"                    $this->query->bind(\'data__\' . $key, $val, isset($bind[$key]) ? $bind[$key] : PDO::PARAM_STR);\n"
	"                    $result[$item] = \':data__\' . $key;\n"
	"                }\n"
	"            }\n"
	"        }\n"
	"        return $result;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 字段名分析\n"
	"     * @access protected\n"
	"     * @param string $key\n"
	"     * @param array  $options\n"
	"     * @return string\n"
	"     */\n"
	"    protected function parseKey($key, $options = [], $strict = false)\n"
	"    {\n"
	"        return $key;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * value分析\n"
	"     * @access protected\n"
	"     * @param mixed     $value\n"
	"     * @param string    $field\n"
	"     * @return string|array\n"
	"     */\n"
	"    protected function parseValue($value, $field = \'\')\n"
	"    {\n"
	"        if (is_string($value)) {\n"
	"            $value = strpos($value, \':\') === 0 && $this->query->isBind(substr($value, 1)) ? $value : $this->connection->quote($value);\n"
	"        } elseif (is_array($value)) {\n"
	"            $value = array_map([$this, \'parseValue\'], $value);\n"
	"        } elseif (is_bool($value)) {\n"
	"            $value = $value ? \'1\' : \'0\';\n"
	"        } elseif (is_null($value)) {\n"
	"            $value = \'null\';\n"
	"        }\n"
	"        return $value;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * field分析\n"
	"     * @access protected\n"
	"     * @param mixed     $fields\n"
	"     * @param array     $options\n"
	"     * @return string\n"
	"     */\n"
	"    protected function parseField($fields, $options = [])\n"
	"    {\n"
	"        if (\'*\' == $fields || empty($fields)) {\n"
	"            $fieldsStr = \'*\';\n"
	"        } elseif (is_array($fields)) {\n"
	"            // 支持 \'field1\'=>\'field2\' 这样的字段别名定义\n"
	"            $array = [];\n"
	"            foreach ($fields as $key => $field) {\n"
	"                if ($field instanceof Expression) {\n"
	"                    $array[] = $field->getValue();\n"
	"                } elseif (!is_numeric($key)) {\n"
	"                    $array[] = $this->parseKey($key, $options) . \' AS \' . $this->parseKey($field, $options, true);\n"
	"                } else {\n"
	"                    $array[] = $this->parseKey($field, $options);\n"
	"                }\n"
	"            }\n"
	"            $fieldsStr = implode(\',\', $array);\n"
	"        }\n"
	"        return $fieldsStr;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * table分析\n"
	"     * @access protected\n"
	"     * @param mixed $tables\n"
	"     * @param array $options\n"
	"     * @return string\n"
	"     */\n"
	"    protected function parseTable($tables, $options = [])\n"
	"    {\n"
	"        $item = [];\n"
	"        foreach ((array) $tables as $key => $table) {\n"
	"            if (!is_numeric($key)) {\n"
	"                $key    = $this->parseSqlTable($key);\n"
	"                $item[] = $this->parseKey($key) . \' \' . (isset($options[\'alias\'][$table]) ? $this->parseKey($options[\'alias\'][$table]) : $this->parseKey($table));\n"
	"            } else {\n"
	"                $table = $this->parseSqlTable($table);\n"
	"                if (isset($options[\'alias\'][$table])) {\n"
	"                    $item[] = $this->parseKey($table) . \' \' . $this->parseKey($options[\'alias\'][$table]);\n"
	"                } else {\n"
	"                    $item[] = $this->parseKey($table);\n"
	"                }\n"
	"            }\n"
	"        }\n"
	"        return implode(\',\', $item);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * where分析\n"
	"     * @access protected\n"
	"     * @param mixed $where   查询条件\n"
	"     * @param array $options 查询参数\n"
	"     * @return string\n"
	"     */\n"
	"    protected function parseWhere($where, $options)\n"
	"    {\n"
	"        $whereStr = $this->buildWhere($where, $options);\n"
	"        if (!empty($options[\'soft_delete\'])) {\n"
	"            // 附加软删除条件\n"
	"            list($field, $condition) = $options[\'soft_delete\'];\n"
	"\n"
	"            $binds    = $this->query->getFieldsBind($options[\'table\']);\n"
	"            $whereStr = $whereStr ? \'( \' . $whereStr . \' ) AND \' : \'\';\n"
	"            $whereStr = $whereStr . $this->parseWhereItem($field, $condition, \'\', $options, $binds);\n"
	"        }\n"
	"        return empty($whereStr) ? \'\' : \' WHERE \' . $whereStr;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 生成查询条件SQL\n"
	"     * @access public\n"
	"     * @param mixed     $where\n"
	"     * @param array     $options\n"
	"     * @return string\n"
	"     */\n"
	"    public function buildWhere($where, $options)\n"
	"    {\n"
	"        if (empty($where)) {\n"
	"            $where = [];\n"
	"        }\n"
	"\n"
	"        if ($where instanceof Query) {\n"
	"            return $this->buildWhere($where->getOptions(\'where\'), $options);\n"
	"        }\n"
	"\n"
	"        $whereStr = \'\';\n"
	"        $binds    = $this->query->getFieldsBind($options[\'table\']);\n"
	"        foreach ($where as $key => $val) {\n"
	"            $str = [];\n"
	"            foreach ($val as $field => $value) {\n"
	"                if ($value instanceof Expression) {\n"
	"                    $str[] = \' \' . $key . \' ( \' . $value->getValue() . \' )\';\n"
	"                } elseif ($value instanceof \\Closure) {\n"
	"                    // 使用闭包查询\n"
	"                    $query = new Query($this->connection);\n"
	"                    call_user_func_array($value, [ & $query]);\n"
	"                    $whereClause = $this->buildWhere($query->getOptions(\'where\'), $options);\n"
	"                    if (!empty($whereClause)) {\n"
	"                        $str[] = \' \' . $key . \' ( \' . $whereClause . \' )\';\n"
	"                    }\n"
	"                } elseif (strpos($field, \'|\')) {\n"
	"                    // 不同字段使用相同查询条件（OR）\n"
	"                    $array = explode(\'|\', $field);\n"
	"                    $item  = [];\n"
	"                    foreach ($array as $k) {\n"
	"                        $item[] = $this->parseWhereItem($k, $value, \'\', $options, $binds);\n"
	"                    }\n"
	"                    $str[] = \' \' . $key . \' ( \' . implode(\' OR \', $item) . \' )\';\n"
	"                } elseif (strpos($field, \'&\')) {\n"
	"                    // 不同字段使用相同查询条件（AND）\n"
	"                    $array = explode(\'&\', $field);\n"
	"                    $item  = [];\n"
	"                    foreach ($array as $k) {\n"
	"                        $item[] = $this->parseWhereItem($k, $value, \'\', $options, $binds);\n"
	"                    }\n"
	"                    $str[] = \' \' . $key . \' ( \' . implode(\' AND \', $item) . \' )\';\n"
	"                } else {\n"
	"                    // 对字段使用表达式查询\n"
	"                    $field = is_string($field) ? $field : \'\';\n"
	"                    $str[] = \' \' . $key . \' \' . $this->parseWhereItem($field, $value, $key, $options, $binds);\n"
	"                }\n"
	"            }\n"
	"\n"
	"            $whereStr .= empty($whereStr) ? substr(implode(\' \', $str), strlen($key) + 1) : implode(\' \', $str);\n"
	"        }\n"
	"\n"
	"        return $whereStr;\n"
	"    }\n"
	"\n"
	"    // where子单元分析\n"
	"    protected function parseWhereItem($field, $val, $rule = \'\', $options = [], $binds = [], $bindName = null)\n"
	"    {\n"
	"        // 字段分析\n"
	"        $key = $field ? $this->parseKey($field, $options, true) : \'\';\n"
	"\n"
	"        // 查询规则和条件\n"
	"        if (!is_array($val)) {\n"
	"            $val = is_null($val) ? [\'null\', \'\'] : [\'=\', $val];\n"
	"        }\n"
	"        list($exp, $value) = $val;\n"
	"\n"
	"        // 对一个字段使用多个查询条件\n"
	"        if (is_array($exp)) {\n"
	"            $item = array_pop($val);\n"
	"            // 传入 or 或者 and\n"
	"            if (is_string($item) && in_array($item, [\'AND\', \'and\', \'OR\', \'or\'])) {\n"
	"                $rule = $item;\n"
	"            } else {\n"
	"                array_push($val, $item);\n"
	"            }\n"
	"            foreach ($val as $k => $item) {\n"
	"                $bindName = \'where_\' . str_replace(\'.\', \'_\', $field) . \'_\' . $k;\n"
	"                $str[]    = $this->parseWhereItem($field, $item, $rule, $options, $binds, $bindName);\n"
	"            }\n"
	"            return \'( \' . implode(\' \' . $rule . \' \', $str) . \' )\';\n"
	"        }\n"
	"\n"
	"        // 检测操作符\n"
	"        if (!in_array($exp, $this->exp)) {\n"
	"            $exp = strtolower($exp);\n"
	"            if (isset($this->exp[$exp])) {\n"
	"                $exp = $this->exp[$exp];\n"
	"            } else {\n"
	"                throw new Exception(\'where express error:\' . $exp);\n"
	"            }\n"
	"        }\n"
	"        $bindName = $bindName ?: \'where_\' . $rule . \'_\' . str_replace([\'.\', \'-\'], \'_\', $field);\n"
	"        if (preg_match(\'/\\W/\', $bindName)) {\n"
	"            // 处理带非单词字符的字段名\n"
	"            $bindName = md5($bindName);\n"
	"        }\n"
	"\n"
	"        if ($value instanceof Expression) {\n"
	"\n"
	"        } elseif (is_object($value) && method_exists($value, \'__toString\')) {\n"
	"            // 对象数据写入\n"
	"            $value = $value->__toString();\n"
	"        }\n"
	"\n"
	"        $bindType = isset($binds[$field]) ? $binds[$field] : PDO::PARAM_STR;\n"
	"        if (is_scalar($value) && array_key_exists($field, $binds) && !in_array($exp, [\'EXP\', \'NOT NULL\', \'NULL\', \'IN\', \'NOT IN\', \'BETWEEN\', \'NOT BETWEEN\']) && strpos($exp, \'TIME\') === false) {\n"
	"            if (strpos($value, \':\') !== 0 || !$this->query->isBind(substr($value, 1))) {\n"
	"                if ($this->query->isBind($bindName)) {\n"
	"                    $bindName .= \'_\' . str_replace(\'.\', \'_\', uniqid(\'\', true));\n"
	"                }\n"
	"                $this->query->bind($bindName, $value, $bindType);\n"
	"                $value = \':\' . $bindName;\n"
	"            }\n"
	"        }\n"
	"\n"
	"        $whereStr = \'\';\n"
	"        if (in_array($exp, [\'=\', \'<>\', \'>\', \'>=\', \'<\', \'<=\'])) {\n"
	"            // 比较运算\n"
	"            if ($value instanceof \\Closure) {\n"
	"                $whereStr .= $key . \' \' . $exp . \' \' . $this->parseClosure($value);\n"
	"            } else {\n"
	"                $whereStr .= $key . \' \' . $exp . \' \' . $this->parseValue($value, $field);\n"
	"            }\n"
	"        } elseif (\'LIKE\' == $exp || \'NOT LIKE\' == $exp) {\n"
	"            // 模糊匹配\n"
	"            if (is_array($value)) {\n"
	"                foreach ($value as $item) {\n"
	"                    $array[] = $key . \' \' . $exp . \' \' . $this->parseValue($item, $field);\n"
	"                }\n"
	"                $logic = isset($val[2]) ? $val[2] : \'AND\';\n"
	"                $whereStr .= \'(\' . implode($array, \' \' . strtoupper($logic) . \' \') . \')\';\n"
	"            } else {\n"
	"                $whereStr .= $key . \' \' . $exp . \' \' . $this->parseValue($value, $field);\n"
	"            }\n"
	"        } elseif (\'EXP\' == $exp) {\n"
	"            // 表达式查询\n"
	"            if ($value instanceof Expression) {\n"
	"                $whereStr .= \'( \' . $key . \' \' . $value->getValue() . \' )\';\n"
	"            } else {\n"
	"                throw new Exception(\'where express error:\' . $exp);\n"
	"            }\n"
	"        } elseif (in_array($exp, [\'NOT NULL\', \'NULL\'])) {\n"
	"            // NULL 查询\n"
	"            $whereStr .= $key . \' IS \' . $exp;\n"
	"        } elseif (in_array($exp, [\'NOT IN\', \'IN\'])) {\n"
	"            // IN 查询\n"
	"            if ($value instanceof \\Closure) {\n"
	"                $whereStr .= $key . \' \' . $exp . \' \' . $this->parseClosure($value);\n"
	"            } else {\n"
	"                $value = array_unique(is_array($value) ? $value : explode(\',\', $value));\n"
	"                if (array_key_exists($field, $binds)) {\n"
	"                    $bind  = [];\n"
	"                    $array = [];\n"
	"                    $i     = 0;\n"
	"                    foreach ($value as $v) {\n"
	"                        $i++;\n"
	"                        if ($this->query->isBind($bindName . \'_in_\' . $i)) {\n"
	"                            $bindKey = $bindName . \'_in_\' . uniqid() . \'_\' . $i;\n"
	"                        } else {\n"
	"                            $bindKey = $bindName . \'_in_\' . $i;\n"
	"                        }\n"
	"                        $bind[$bindKey] = [$v, $bindType];\n"
	"                        $array[]        = \':\' . $bindKey;\n"
	"                    }\n"
	"                    $this->query->bind($bind);\n"
	"                    $zone = implode(\',\', $array);\n"
	"                } else {\n"
	"                    $zone = implode(\',\', $this->parseValue($value, $field));\n"
	"                }\n"
	"                $whereStr .= $key . \' \' . $exp . \' (\' . (empty($zone) ? \"\'\'\" : $zone) . \')\';\n"
	"            }\n"
	"        } elseif (in_array($exp, [\'NOT BETWEEN\', \'BETWEEN\'])) {\n"
	"            // BETWEEN 查询\n"
	"            $data = is_array($value) ? $value : explode(\',\', $value);\n"
	"            if (array_key_exists($field, $binds)) {\n"
	"                if ($this->query->isBind($bindName . \'_between_1\')) {\n"
	"                    $bindKey1 = $bindName . \'_between_1\' . uniqid();\n"
	"                    $bindKey2 = $bindName . \'_between_2\' . uniqid();\n"
	"                } else {\n"
	"                    $bindKey1 = $bindName . \'_between_1\';\n"
	"                    $bindKey2 = $bindName . \'_between_2\';\n"
	"                }\n"
	"                $bind = [\n"
	"                    $bindKey1 => [$data[0], $bindType],\n"
	"                    $bindKey2 => [$data[1], $bindType],\n"
	"                ];\n"
	"                $this->query->bind($bind);\n"
	"                $between = \':\' . $bindKey1 . \' AND :\' . $bindKey2;\n"
	"            } else {\n"
	"                $between = $this->parseValue($data[0], $field) . \' AND \' . $this->parseValue($data[1], $field);\n"
	"            }\n"
	"            $whereStr .= $key . \' \' . $exp . \' \' . $between;\n"
	"        } elseif (in_array($exp, [\'NOT EXISTS\', \'EXISTS\'])) {\n"
	"            // EXISTS 查询\n"
	"            if ($value instanceof \\Closure) {\n"
	"                $whereStr .= $exp . \' \' . $this->parseClosure($value);\n"
	"            } else {\n"
	"                $whereStr .= $exp . \' (\' . $value . \')\';\n"
	"            }\n"
	"        } elseif (in_array($exp, [\'< TIME\', \'> TIME\', \'<= TIME\', \'>= TIME\'])) {\n"
	"            $whereStr .= $key . \' \' . substr($exp, 0, 2) . \' \' . $this->parseDateTime($value, $field, $options, $bindName, $bindType);\n"
	"        } elseif (in_array($exp, [\'BETWEEN TIME\', \'NOT BETWEEN TIME\'])) {\n"
	"            if (is_string($value)) {\n"
	"                $value = explode(\',\', $value);\n"
	"            }\n"
	"\n"
	"            $whereStr .= $key . \' \' . substr($exp, 0, -4) . $this->parseDateTime($value[0], $field, $options, $bindName . \'_between_1\', $bindType) . \' AND \' . $this->parseDateTime($value[1], $field, $options, $bindName . \'_between_2\', $bindType);\n"
	"        }\n"
	"        return $whereStr;\n"
	"    }\n"
	"\n"
	"    // 执行闭包子查询\n"
	"    protected function parseClosure($call, $show = true)\n"
	"    {\n"
	"        $query = new Query($this->connection);\n"
	"        call_user_func_array($call, [ & $query]);\n"
	"        return $query->buildSql($show);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 日期时间条件解析\n"
	"     * @access protected\n"
	"     * @param string    $value\n"
	"     * @param string    $key\n"
	"     * @param array     $options\n"
	"     * @param string    $bindName\n"
	"     * @param integer   $bindType\n"
	"     * @return string\n"
	"     */\n"
	"    protected function parseDateTime($value, $key, $options = [], $bindName = null, $bindType = null)\n"
	"    {\n"
	"        // 获取时间字段类型\n"
	"        if (strpos($key, \'.\')) {\n"
	"            list($table, $key) = explode(\'.\', $key);\n"
	"            if (isset($options[\'alias\']) && $pos = array_search($table, $options[\'alias\'])) {\n"
	"                $table = $pos;\n"
	"            }\n"
	"        } else {\n"
	"            $table = $options[\'table\'];\n"
	"        }\n"
	"        $type = $this->query->getTableInfo($table, \'type\');\n"
	"        if (isset($type[$key])) {\n"
	"            $info = $type[$key];\n"
	"        }\n"
	"        if (isset($info)) {\n"
	"            if (is_string($value)) {\n"
	"                $value = strtotime($value) ?: $value;\n"
	"            }\n"
	"\n"
	"            if (preg_match(\'/(datetime|timestamp)/is\', $info)) {\n"
	"                // 日期及时间戳类型\n"
	"                $value = date(\'Y-m-d H:i:s\', $value);\n"
	"            } elseif (preg_match(\'/(date)/is\', $info)) {\n"
	"                // 日期及时间戳类型\n"
	"                $value = date(\'Y-m-d\', $value);\n"
	"            }\n"
	"        }\n"
	"        $bindName = $bindName ?: $key;\n"
	"\n"
	"        if ($this->query->isBind($bindName)) {\n"
	"            $bindName .= \'_\' . str_replace(\'.\', \'_\', uniqid(\'\', true));\n"
	"        }\n"
	"\n"
	"        $this->query->bind($bindName, $value, $bindType);\n"
	"        return \':\' . $bindName;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * limit分析\n"
	"     * @access protected\n"
	"     * @param mixed $limit\n"
	"     * @return string\n"
	"     */\n"
	"    protected function parseLimit($limit)\n"
	"    {\n"
	"        return (!empty($limit) && false === strpos($limit, \'(\')) ? \' LIMIT \' . $limit . \' \' : \'\';\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * join分析\n"
	"     * @access protected\n"
	"     * @param array $join\n"
	"     * @param array $options 查询条件\n"
	"     * @return string\n"
	"     */\n"
	"    protected function parseJoin($join, $options = [])\n"
	"    {\n"
	"        $joinStr = \'\';\n"
	"        if (!empty($join)) {\n"
	"            foreach ($join as $item) {\n"
	"                list($table, $type, $on) = $item;\n"
	"                $condition               = [];\n"
	"                foreach ((array) $on as $val) {\n"
	"                    if ($val instanceof Expression) {\n"
	"                        $condition[] = $val->getValue();\n"
	"                    } elseif (strpos($val, \'=\')) {\n"
	"                        list($val1, $val2) = explode(\'=\', $val, 2);\n"
	"                        $condition[]       = $this->parseKey($val1, $options) . \'=\' . $this->parseKey($val2, $options);\n"
	"                    } else {\n"
	"                        $condition[] = $val;\n"
	"                    }\n"
	"                }\n"
	"\n"
	"                $table = $this->parseTable($table, $options);\n"
	"                $joinStr .= \' \' . $type . \' JOIN \' . $table . \' ON \' . implode(\' AND \', $condition);\n"
	"            }\n"
	"        }\n"
	"        return $joinStr;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * order分析\n"
	"     * @access protected\n"
	"     * @param mixed $order\n"
	"     * @param array $options 查询条件\n"
	"     * @return string\n"
	"     */\n"
	"    protected function parseOrder($order, $options = [])\n"
	"    {\n"
	"        if (empty($order)) {\n"
	"            return \'\';\n"
	"        }\n"
	"\n"
	"        $array = [];\n"
	"        foreach ($order as $key => $val) {\n"
	"            if ($val instanceof Expression) {\n"
	"                $array[] = $val->getValue();\n"
	"            } elseif (\'[rand]\' == $val) {\n"
	"                $array[] = $this->parseRand();\n"
	"            } else {\n"
	"                if (is_numeric($key)) {\n"
	"                    list($key, $sort) = explode(\' \', strpos($val, \' \') ? $val : $val . \' \');\n"
	"                } else {\n"
	"                    $sort = $val;\n"
	"                }\n"
	"                $sort    = strtoupper($sort);\n"
	"                $sort    = in_array($sort, [\'ASC\', \'DESC\'], true) ? \' \' . $sort : \'\';\n"
	"                $array[] = $this->parseKey($key, $options, true) . $sort;\n"
	"            }\n"
	"        }\n"
	"        $order = implode(\',\', $array);\n"
	"\n"
	"        return !empty($order) ? \' ORDER BY \' . $order : \'\';\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * group分析\n"
	"     * @access protected\n"
	"     * @param mixed $group\n"
	"     * @return string\n"
	"     */\n"
	"    protected function parseGroup($group)\n"
	"    {\n"
	"        return !empty($group) ? \' GROUP BY \' . $this->parseKey($group) : \'\';\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * having分析\n"
	"     * @access protected\n"
	"     * @param string $having\n"
	"     * @return string\n"
	"     */\n"
	"    protected function parseHaving($having)\n"
	"    {\n"
	"        return !empty($having) ? \' HAVING \' . $having : \'\';\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * comment分析\n"
	"     * @access protected\n"
	"     * @param string $comment\n"
	"     * @return string\n"
	"     */\n"
	"    protected function parseComment($comment)\n"
	"    {\n"
	"        if (false !== strpos($comment, \'*/\')) {\n"
	"            $comment = strstr($comment, \'*/\', true);\n"
	"        }\n"
	"        return !empty($comment) ? \' /* \' . $comment . \' */\' : \'\';\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * distinct分析\n"
	"     * @access protected\n"
	"     * @param mixed $distinct\n"
	"     * @return string\n"
	"     */\n"
	"    protected function parseDistinct($distinct)\n"
	"    {\n"
	"        return !empty($distinct) ? \' DISTINCT \' : \'\';\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * union分析\n"
	"     * @access protected\n"
	"     * @param mixed $union\n"
	"     * @return string\n"
	"     */\n"
	"    protected function parseUnion($union)\n"
	"    {\n"
	"        if (empty($union)) {\n"
	"            return \'\';\n"
	"        }\n"
	"        $type = $union[\'type\'];\n"
	"        unset($union[\'type\']);\n"
	"        foreach ($union as $u) {\n"
	"            if ($u instanceof \\Closure) {\n"
	"                $sql[] = $type . \' \' . $this->parseClosure($u);\n"
	"            } elseif (is_string($u)) {\n"
	"                $sql[] = $type . \' ( \' . $this->parseSqlTable($u) . \' )\';\n"
	"            }\n"
	"        }\n"
	"        return \' \' . implode(\' \', $sql);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * index分析，可在操作链中指定需要强制使用的索引\n"
	"     * @access protected\n"
	"     * @param mixed $index\n"
	"     * @return string\n"
	"     */\n"
	"    protected function parseForce($index)\n"
	"    {\n"
	"        if (empty($index)) {\n"
	"            return \'\';\n"
	"        }\n"
	"\n"
	"        return sprintf(\" FORCE INDEX ( %s ) \", is_array($index) ? implode(\',\', $index) : $index);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 设置锁机制\n"
	"     * @access protected\n"
	"     * @param bool|string $lock\n"
	"     * @return string\n"
	"     */\n"
	"    protected function parseLock($lock = false)\n"
	"    {\n"
	"        if (is_bool($lock)) {\n"
	"            return $lock ? \' FOR UPDATE \' : \'\';\n"
	"        } elseif (is_string($lock)) {\n"
	"            return \' \' . trim($lock) . \' \';\n"
	"        }\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 生成查询SQL\n"
	"     * @access public\n"
	"     * @param array $options 表达式\n"
	"     * @return string\n"
	"     */\n"
	"    public function select($options = [])\n"
	"    {\n"
	"        $sql = str_replace(\n"
	"            [\'%TABLE%\', \'%DISTINCT%\', \'%FIELD%\', \'%JOIN%\', \'%WHERE%\', \'%GROUP%\', \'%HAVING%\', \'%ORDER%\', \'%LIMIT%\', \'%UNION%\', \'%LOCK%\', \'%COMMENT%\', \'%FORCE%\'],\n"
	"            [\n"
	"                $this->parseTable($options[\'table\'], $options),\n"
	"                $this->parseDistinct($options[\'distinct\']),\n"
	"                $this->parseField($options[\'field\'], $options),\n"
	"                $this->parseJoin($options[\'join\'], $options),\n"
	"                $this->parseWhere($options[\'where\'], $options),\n"
	"                $this->parseGroup($options[\'group\']),\n"
	"                $this->parseHaving($options[\'having\']),\n"
	"                $this->parseOrder($options[\'order\'], $options),\n"
	"                $this->parseLimit($options[\'limit\']),\n"
	"                $this->parseUnion($options[\'union\']),\n"
	"                $this->parseLock($options[\'lock\']),\n"
	"                $this->parseComment($options[\'comment\']),\n"
	"                $this->parseForce($options[\'force\']),\n"
	"            ], $this->selectSql);\n"
	"        return $sql;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 生成insert SQL\n"
	"     * @access public\n"
	"     * @param array     $data 数据\n"
	"     * @param array     $options 表达式\n"
	"     * @param bool      $replace 是否replace\n"
	"     * @return string\n"
	"     */\n"
	"    public function insert(array $data, $options = [], $replace = false)\n"
	"    {\n"
	"        // 分析并处理数据\n"
	"        $data = $this->parseData($data, $options);\n"
	"        if (empty($data)) {\n"
	"            return 0;\n"
	"        }\n"
	"        $fields = array_keys($data);\n"
	"        $values = array_values($data);\n"
	"\n"
	"        $sql = str_replace(\n"
	"            [\'%INSERT%\', \'%TABLE%\', \'%FIELD%\', \'%DATA%\', \'%COMMENT%\'],\n"
	"            [\n"
	"                $replace ? \'REPLACE\' : \'INSERT\',\n"
	"                $this->parseTable($options[\'table\'], $options),\n"
	"                implode(\' , \', $fields),\n"
	"                implode(\' , \', $values),\n"
	"                $this->parseComment($options[\'comment\']),\n"
	"            ], $this->insertSql);\n"
	"\n"
	"        return $sql;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 生成insertall SQL\n"
	"     * @access public\n"
	"     * @param array     $dataSet 数据集\n"
	"     * @param array     $options 表达式\n"
	"     * @param bool      $replace 是否replace\n"
	"     * @return string\n"
	"     * @throws Exception\n"
	"     */\n"
	"    public function insertAll($dataSet, $options = [], $replace = false)\n"
	"    {\n"
	"        // 获取合法的字段\n"
	"        if (\'*\' == $options[\'field\']) {\n"
	"            $fields = array_keys($this->query->getFieldsType($options[\'table\']));\n"
	"        } else {\n"
	"            $fields = $options[\'field\'];\n"
	"        }\n"
	"\n"
	"        foreach ($dataSet as $data) {\n"
	"            foreach ($data as $key => $val) {\n"
	"                if (!in_array($key, $fields, true)) {\n"
	"                    if ($options[\'strict\']) {\n"
	"                        throw new Exception(\'fields not exists:[\' . $key . \']\');\n"
	"                    }\n"
	"                    unset($data[$key]);\n"
	"                } elseif (is_null($val)) {\n"
	"                    $data[$key] = \'NULL\';\n"
	"                } elseif (is_scalar($val)) {\n"
	"                    $data[$key] = $this->parseValue($val, $key);\n"
	"                } elseif (is_object($val) && method_exists($val, \'__toString\')) {\n"
	"                    // 对象数据写入\n"
	"                    $data[$key] = $val->__toString();\n"
	"                } else {\n"
	"                    // 过滤掉非标量数据\n"
	"                    unset($data[$key]);\n"
	"                }\n"
	"            }\n"
	"            $value    = array_values($data);\n"
	"            $values[] = \'SELECT \' . implode(\',\', $value);\n"
	"\n"
	"            if (!isset($insertFields)) {\n"
	"                $insertFields = array_keys($data);\n"
	"            }\n"
	"        }\n"
	"\n"
	"        foreach ($insertFields as $field) {\n"
	"            $fields[] = $this->parseKey($field, $options, true);\n"
	"        }\n"
	"\n"
	"        return str_replace(\n"
	"            [\'%INSERT%\', \'%TABLE%\', \'%FIELD%\', \'%DATA%\', \'%COMMENT%\'],\n"
	"            [\n"
	"                $replace ? \'REPLACE\' : \'INSERT\',\n"
	"                $this->parseTable($options[\'table\'], $options),\n"
	"                implode(\' , \', $insertFields),\n"
	"                implode(\' UNION ALL \', $values),\n"
	"                $this->parseComment($options[\'comment\']),\n"
	"            ], $this->insertAllSql);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 生成select insert SQL\n"
	"     * @access public\n"
	"     * @param array     $fields 数据\n"
	"     * @param string    $table 数据表\n"
	"     * @param array     $options 表达式\n"
	"     * @return string\n"
	"     */\n"
	"    public function selectInsert($fields, $table, $options)\n"
	"    {\n"
	"        if (is_string($fields)) {\n"
	"            $fields = explode(\',\', $fields);\n"
	"        }\n"
	"\n"
	"        $fields = array_map([$this, \'parseKey\'], $fields);\n"
	"        $sql    = \'INSERT INTO \' . $this->parseTable($table, $options) . \' (\' . implode(\',\', $fields) . \') \' . $this->select($options);\n"
	"        return $sql;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 生成update SQL\n"
	"     * @access public\n"
	"     * @param array     $data 数据\n"
	"     * @param array     $options 表达式\n"
	"     * @return string\n"
	"     */\n"
	"    public function update($data, $options)\n"
	"    {\n"
	"        $table = $this->parseTable($options[\'table\'], $options);\n"
	"        $data  = $this->parseData($data, $options);\n"
	"        if (empty($data)) {\n"
	"            return \'\';\n"
	"        }\n"
	"        foreach ($data as $key => $val) {\n"
	"            $set[] = $key . \'=\' . $val;\n"
	"        }\n"
	"\n"
	"        $sql = str_replace(\n"
	"            [\'%TABLE%\', \'%SET%\', \'%JOIN%\', \'%WHERE%\', \'%ORDER%\', \'%LIMIT%\', \'%LOCK%\', \'%COMMENT%\'],\n"
	"            [\n"
	"                $this->parseTable($options[\'table\'], $options),\n"
	"                implode(\',\', $set),\n"
	"                $this->parseJoin($options[\'join\'], $options),\n"
	"                $this->parseWhere($options[\'where\'], $options),\n"
	"                $this->parseOrder($options[\'order\'], $options),\n"
	"                $this->parseLimit($options[\'limit\']),\n"
	"                $this->parseLock($options[\'lock\']),\n"
	"                $this->parseComment($options[\'comment\']),\n"
	"            ], $this->updateSql);\n"
	"\n"
	"        return $sql;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 生成delete SQL\n"
	"     * @access public\n"
	"     * @param array $options 表达式\n"
	"     * @return string\n"
	"     */\n"
	"    public function delete($options)\n"
	"    {\n"
	"        $sql = str_replace(\n"
	"            [\'%TABLE%\', \'%USING%\', \'%JOIN%\', \'%WHERE%\', \'%ORDER%\', \'%LIMIT%\', \'%LOCK%\', \'%COMMENT%\'],\n"
	"            [\n"
	"                $this->parseTable($options[\'table\'], $options),\n"
	"                !empty($options[\'using\']) ? \' USING \' . $this->parseTable($options[\'using\'], $options) . \' \' : \'\',\n"
	"                $this->parseJoin($options[\'join\'], $options),\n"
	"                $this->parseWhere($options[\'where\'], $options),\n"
	"                $this->parseOrder($options[\'order\'], $options),\n"
	"                $this->parseLimit($options[\'limit\']),\n"
	"                $this->parseLock($options[\'lock\']),\n"
	"                $this->parseComment($options[\'comment\']),\n"
	"            ], $this->deleteSql);\n"
	"\n"
	"        return $sql;\n"
	"    }\n"
	"}\n"
	"\n"
;
#endif